<?php
//http://maps.yandex.ru/services/search/1.x/search.json?autoscale=0&lang=ru-RU&ll=29.241688,50.502007&origin=maps-pager&results=10&text=%D0%A1%D0%B8%D0%BB%D1%8C%D0%BF%D0%BE&lang=en_US
//http://geocode-maps.yandex.ru/1.x/?geocode=E134.854,S25.828
//http://geocode-maps.yandex.ru/1.x/?geocode=Москва,+Тверская+улица,+дом+7

include_once $_SERVER['DOCUMENT_ROOT'].'/lib/Cache.php';

class Yandex{
	private $key='AF7QzFMBAAAAdlo7JAQAb321Kno4oOKXe5D9gcMHD3GLG2cAAAAAAAAAAAByeig0LrTNe2bGYId2CdPhChcLIA==';
	private $lang='ru_RU';
	private $supportedLangs=array( 'ru_RU','uk_UA','be_BY','en_US' );
	public	$curJson=false;

	protected static $_instance;
	private function __construct(){}
	private function __clone(){}
	public static function inst(){
	  if( null===self::$_instance ){
	    self::$_instance=new self();
		}
		return self::$_instance;
	}
	
	protected $errors=array('err'=>array(),'wrn'=>array());
	protected function error($msg){ $this->errors['err'][]=$msg; return false;}
	protected function warning($msg){ $this->errors['wrn'][]=$msg; return false;}
	public function getError(){ return $this->errors['err'][ count($this->errors['err'])-1 ]; }
	public function getErrors(){ return $this->errors['err']; }
	public function getWarning(){ return $this->errors['wrn'][ count($this->errors['wrn'])-1 ]; }
	public function getWarnings(){ return $this->errors['wrn']; }


	function setLang($ln){
	  //if( !in_array($ln, $this->supportedLangs) ) return false;
		for($i=0,$set=false; $i<4; $i++){
		  if( substr($this->supportedLangs[$i], 0,2)==$ln ) $set=$this->supportedLangs[$i];
		}
	  if(!$set) return false;

	  $this->lang=$set; return true;
	}
	
	/**************************
	 *	Произвольный запрос к API
	***************************/
	function request($query,$headers=array()){
		// Create a stream
		// File_get_content with headers http://stackoverflow.com/questions/2107759/php-file-get-contents-and-headers
		$context = stream_context_create(
			array(
			  'http'=>array(
			    'method'=>"GET",
			    'header'=> implode("\r\n",$headers) //"Accept-language: en\r\n"
			  )
			)
		);
		
	  $json=file_get_contents($query, false, $context);

	  if(empty($json)) return $this->error('Empty yandex response');
		
	  $dt=json_decode($json);
	  $this->curJson=$json;

		return $dt;
	}
	
	/**
   * Makes request to google maps API to make geocode;
   * @name geocode
   * @author  John Bor <johncomua@gmail.com>
   * @param array @reg  array(addr(or lat,lng,radius),query, lang, country, region, city)
   */
	function geocode($req){
	  if( is_string($req) ) $req=array('addr'=>$req);
	  
	  if(empty($req['addr']) && (empty($req['lat']) ||  empty($req['lng'])) ){
			return $this->error('Не переданы параметры геокодинга Yandex');
		}
		
		$query='http://geocode-maps.yandex.ru/1.x/?format=json';
		
	  if( !empty( $req['lang'] ) ) $this->setLang($req['lang']);
	  
		if(!empty($req['addr'])){
			if(strpos($req['addr'], '/')!==false) $req['addr']=substr($req['addr'], 0, strpos($req['addr'], '/'));
			$req['addr']=trim($req['addr']);
			$req['addr']=strtr($req['addr'], array("'"=>'','"'=>'','`'=>''));
			$req['addr']=urlencode($req['addr']);
			
			$query.='?geocode='.$req['addr'].'&results=1&language='.$this->lang.'&key='.$this->key;
		}else{
		  $query.='?geocode='.$req['lat'].','.$req['lng'].'&kind=house&sco=latlong&language='.$this->lang;
		}
		
		//Извлекаю из кеша
		if($tst=Cache::inst()->get($query) ){
	     return $tst;
		}

    $googleInfo=$this->request($query);
//echo '<pre class="debug">'.print_r ( $googleInfo ,true).'</pre>';exit();
		if( empty($googleInfo->results) ){
	    return $this->error('empty Yandex geocode response');
		}
		/*
		$results=array();
		if(!empty($req['filter'])){
		  for( $r=0, $rcnt=count($googleInfo->results); $r<$rcnt; $r++ ){
		    $match=true;
			  for( $f=0, $fcnt=count($req['filter']); $f<$fcnt; $f++  ){
			    for( $i=0, $cnt=count($googleInfo->results[$r]->address_components[$f]->types); $i<$cnt; $i++ ){
			      if( strpos($req['filter'][$f],$googleInfo->results[$r]->address_components[$f]->types[$i])===false ){
			        $match=false;
			        break 2;
						}
					}
				}
				if($match) $results[]=$googleInfo->results[$r];
		  }
		  //echo 'FILTERED:<pre class="debug">'.print_r ( $results ,true).'</pre>';exit();
		  $googleInfo->results=$results;
		  unset($results, $match, $rcnt,$fcnt,$cnt, $f,$f,$i);
		}
		*/
		$geoDetail=$this->parsegeoDetails($googleInfo->results[0]);
		
   //кеширую
	  if( !Cache::inst()->set( $query, $geoDetail ) ){
	    //echo '<pre class="debug">'.print_r ( Cache::inst()->getErrors() ,true).'</pre>';
	    $this->error('ошибка кеширования - не удалось сохранить данные','wrn');
		}
		
		return $geoDetail;
	}
	
	function parseGeoDetails($result){
		//Формализую результат
		$geoDetail=array(
		  'countryIso'=>false,
		  'country'=>false,
		  'region'=>false,
		  'city'=>false,
		  'urbanarea'=>false,
		  'street'=>false,
		  'number'=>false,
		  'lat'=>false,
		  'lng'=>false,
		  'formatedAddr'=>false,
		  'geometry'=>false,
		);
		$parseSteps=array(
			'Country'=>array('CountryName'=>'country','CountryNameCode'=>'countryIso'),
			'AdministrativeArea'=>array('AdministrativeAreaName'=>'region'),
			'SubAdministrativeArea'=>false,
			'Locality'=>array('LocalityName'=>'city'),
			'Thoroughfare'=>array('ThoroughfareName'=>'street'),
			'Premise'=>array('PremiseNumber'=>'number'),
		);
		
		//Именно в обратном порядке, чвем в гугле
		$geoDetail['lat']=$result->geometry->coordinates[1];
		$geoDetail['lng']=$result->geometry->coordinates[0];
		
		$geoDetail['formatedAddr']=$result->properties->CompanyMetaData->address;
		$geoDetail['geometry']=json_encode($result->geometry);
		
		$cur=&$result->properties->CompanyMetaData->AddressDetails;

		foreach($parseSteps as $psk=>$psv){
			if( empty( $cur->$psk ) ) continue;
			$cur=&$cur->$psk;
			if( empty( $psv ) ) { continue; }
			foreach( $psv as $k=>$v ){
			  //echo '<br />'.$k.' => '.$v.' ('.$v.'='.$cur->$k.')'; exit();
			  if(!empty($cur->$k)) $geoDetail[$v]=$cur->$k;
			}
		}


		if(empty($geoDetail['urbanarea']))$geoDetail['urbanarea']=$geoDetail['city'];
		if(empty($geoDetail['region']))$geoDetail['region']=$geoDetail['country'];
	  return $geoDetail;
	}
	
	
	/**
   * Makes request to google places API to find place near lat lng find(array(lat=>'',lng=>'',query=>'',radius=>''));
   * @name find
   * @author  John Bor <johncomua@gmail.com>
   * @param array @reg  array(lat,lng,query,radius)
   */
	function find($req){
	  if(empty($req['query']) || empty($req['lat']) ||  empty($req['lng']) ){
     	return $this->error('Не переданы параметры поиска объекта в Yandex');
		}

		if(strpos($req['query'], '/')!==false){
		  $req['query']=substr($req['query'], 0, strpos($req['query'], '/'));
		}
		$req['fullQuery']=trim($req['fullQuery']);
		$req['fullQuery']=strtr($req['fullQuery'], array("'"=>'','"'=>'','`'=>''));
		$req['fullQuery']=urlencode($req['fullQuery']);

		if( !empty( $req['lang'] ) ) $this->setLang($req['lang']);

	  //Запрос поиска Места
	  $query='http://maps.yandex.ru/services/search/1.x/search.json?autoscale=0&lang='.$this->lang.'&ll='.$req['lat'].','.$req['lng'].'&origin=maps-pager&results=1&text='.$req['fullQuery'];
	  /*
	    Альтернатива - поиск по пользовательской карте
	    http://psearch-maps.yandex.ru/1.x/?format=json&text=%D0%A0%D0%B0%D0%B4%D0%BE%D0%BC%D1%8B%D1%88%D0%BB%D1%8C,%20%D0%91%D0%BE%D0%BB%D1%8C%D1%88%D0%B0%D1%8F%20%D0%96%D0%B8%D1%82%D0%BE%D0%BC%D0%B8%D1%80%D1%81%D0%BA%D0%B0%D1%8F,%201/2%20%D0%A1%D0%B8%D0%BB%D1%8C%D0%BF%D0%BE&key=AF7QzFMBAAAAdlo7JAQAb321Kno4oOKXe5D9gcMHD3GLG2cAAAAAAAAAAAByeig0LrTNe2bGYId2CdPhChcLIA==
		*/

    //Есть ли в кеше?
		if(!$result=Cache::inst()->get($query) ){
		  $item=$this->request($query,array('Accept-language: '.$this->lang ));

			//Validate response
		  if( empty($item->features) ){
		    return $this->error('Place not found');
			}

			$result=$this->parsegeoDetails($item->features[0]);
			$result['name']=$item->features[0]->properties->name;
			$result['formatted_address']=$item->features[0]->properties->CompanyMetaData->address;
	    $result['url']=((!empty($item->features[0]->properties->CompanyMetaData->url)))?$item->features[0]->properties->CompanyMetaData->url:'';
	    $result['dataProvider']='YA';
	    $result['wideInfo']=$item->features[0];

	    //кеширую
		  if( !Cache::inst()->set( $query, $result, CACHE::day ) ){
		    $this->warning('ошибка кеширования - не удалось сохранить результаты поиска места данные');
			}

		}

	  return $result;
	}
}
?>